﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using HQPadMVC.Helpers;

namespace HQPadMVC.Models
{
    /// <summary>
    /// A context object for a specific character.
    /// This can be initialised with either a real character or
    /// a scratch one that has yet to be saved.
    /// </summary>
    public class CharacterContext
    {
        protected XDocument characterData;

        public XDocument Data {
            get { return characterData; }
            protected set { characterData = value; }
        }

        public bool IsScratch { get; protected set; }

        public string UserName { get; set; }

        protected string name = string.Empty;
        
        public string Name 
        {
            get
            {
                if (IsScratch)
                {
                    CharacterXmlHelper xHelper = new CharacterXmlHelper(ref characterData);
                    XElement characterElement = xHelper.GetCharacterElement();

                    XAttribute nameAttribute = characterElement.Attribute("name");

                    if (nameAttribute == null)
                        return "no name";
                    else
                        return nameAttribute.Value;
                }
                else
                    return name;
            }
            set
            {
                name = value;
                SetName(value);
            }
        }

        public int? CharacterID 
        {
            get
            {
                if (!IsScratch && character != null)
                    return character.CharacterID;
                else
                    return null;
            }
        }
        
        public int? ScratchPadID { 
            get 
            {
                if (IsScratch)
                    return scratchCharacter.ScratchPadID;
                else
                    return null;
            } 
        }

        public bool IsScratchDirty
        {
            get
            {
                if (!IsScratch)
                    throw new InvalidOperationException("It is invalid to check for dirtiness on non scratch pad character object.");

                if (!CharacterID.HasValue)
                    return true;
                else
                    return DateSaved;
            }
        }

        public string SessionID { get; protected set; }

        public DateTime DateSaved { get; protected set; }

        protected ScratchPad scratchCharacter;
        protected Character character;

        public Character Character {
            set
            {
                character = value;
                Data = XDocument.Parse(value.Xml);
                IsScratch = false;
                UserName = value.UserName;
                DateSaved = value.DateSaved;
            }
        }

        public ScratchPad ScratchCharacter
        {
            set
            {
                scratchCharacter = value;
                Data = XDocument.Parse(value.Xml);
                IsScratch = true;
                UserName = value.UserName;
                SessionID = value.SessionID;
                DateSaved = value.DateSaved;
            }
        }


        public CharacterContext()
        { }

        #region Public methods

        /// <summary>
        /// Ensure that any changes to the local xml data doc are copied back to the
        /// database entity object so it can be updated.
        /// </summary>
        public void Save()
        {
            DateTime savedDate = DateTime.Now;
            DateSaved = savedDate;

            if (IsScratch)
            {
                scratchCharacter.Xml = Data.ToString();
                scratchCharacter.DateSaved = savedDate;
            }
            else
                character.Xml = Data.ToString();
        }

        #endregion


        #region Protected methods

        #region SetName
        /// <summary>
        /// Set the character name.
        /// </summary>
        /// <param name="name">The new character name.</param>
        protected void SetName(string name)
        {
            // Save name in xml.
            CharacterXmlHelper xHelper = new CharacterXmlHelper(ref characterData);
            XElement characterElement = xHelper.GetCharacterElement();

            XAttribute nameAttribute = characterElement.Attribute("name");

            if (nameAttribute == null)
            {
                nameAttribute = new XAttribute("name", name);
                characterElement.Add(nameAttribute);
            }
            else
                nameAttribute.SetValue(name);
        }
        #endregion

        protected bool IsDirty()
        {
            return false;
        }
        #endregion
    }
}